BeanFactory
提供了Spring IOC 功能的基础,但它仅仅被直接使用在于其他第三方框架的集成中,现在对于大部分的Spring用户来说,那是太长远的事了。BeanFactory
和它关联的接口,例如BeanFactoryAware
,InitializingBean
,DisposableBean
,现在仍然存在Spring中,是为了向后兼容与大量的第三方框架集成。通常第三方组件不使用更新的替代物如@PostConstruct
或@PreDestory
,以便保留与JDK1.4的兼容性或避免对JSR-250的依赖。
这个章节提供了BeanFactory
和ApplicationContext
额外的背景差异以及如何直接访问IOC容器通过一个典型的单例查找。
除非你有更好的理由,否则尽量使用ApplicationContext
。
ApplicationContext
包含了BeanFactory
的所有功能。通常建议比BeanFactory
优先,除非有一些限制的场合如字节长度对内存有很大的影响时(Applet)。当然,对于绝大多数"典型的"企业应用系统,ApplicationContext
就是你需要使用的。Spring大量使用了BeanPostProcessor
扩展(以便应用代理等功能)。如果你仅仅使用简单的BeanFactory
,则无法使用相当多的支持功能,如事务和AOP。这可能会导致混乱,因为配置并没有错误。
下面的列表列出了BeanFactory
接口和ApplicationContext
接口提供的特性和实现。
表 6.9. Feature Matrix特性表
特性 | BeanFactory | ApplicationContext |
---|---|---|
Bean 实例化/装配 | Yes | Yes |
自动 BeanPostProcessor 注册 | No | Yes |
自动 BeanFactoryPostProcessor 注册 | No | Yes |
便捷的 MessageSource 访问( i18n) | No | Yes |
ApplicationEvent 发送 | No | Yes |
为了给BeanFactory
实现明确地注册一个bean后置处理器,你必须这样写代码:
ConfigurableBeanFactory factory = new XmlBeanFactory(...);
// now register any needed BeanPostProcessor instances
MyBeanPostProcessor postProcessor = new MyBeanPostProcessor();
factory.addBeanPostProcessor(postProcessor);
// now start using the factory
为了给BeanFactory
实现明确地注册一个BeanFactoryPostProcessor
,你必须这样写代码:
XmlBeanFactory factory = new XmlBeanFactory(new FileSystemResource("beans.xml"));
// bring in some property values from a Properties file
PropertyPlaceholderConfigurer cfg = new PropertyPlaceholderConfigurer();
cfg.setLocation(new FileSystemResource("jdbc.properties"));
// now actually do the replacement
cfg.postProcessBeanFactory(factory);
这2个例子中,明确的注册步骤使用不是很方便,这就是为什么各种ApplicationContext
实现者相对于简单的BeanFactory
是更好的选择,特别是当使用BeanFactoryPostProcessor
和BeanPostProcessors
的时候。这些机制实现了重要的功能,例如属性的占位符替换和AOP。
一个应用中的大多数代码最好写成依赖注入(控制反转)的风格,这样代码就和Spring IoC容器无关,它们在被创建时从容器得到自己的依赖,并且完全不知道容器的存在。然而,对于少量需要与其它代码粘合的粘合层代码来说,有时候就需要以一种singleton(或者类似singleton)的方式来访问Spring IoC容器。例如,第三方的代码可能试图(以Class.forName()
的方式)直接构造一个新的对象,但无法强制它们从Spring IoC容器中得到这些对象。如果第三方代码构造的对象只是一个小stub或proxy,并且使用singleton方式访问Spring IoC容器来获得真正的对象,那么大多数的代码(由容器产生的对象)仍然可以使用控制反转。因此大多数的代码依然不需要知道容器的存在,或者它如何被访问,并保持与其它代码的解耦,这样所带来的益处是很显然的。EJB也可以使用这种stub/proxy方案代理到由Spring IoC容器产生的普通的Java实现对象。虽然理想情况下Spring IoC容器不需要是singleton,但是如果每个bean使用它自己的non-singleton的Spring IoC容器(当在Spring IoC容器中使用bean时,如Hibernate SessionFactory
),对于内存使用或初始化次数都是不切实际。
你可以查看SingletonBeanFactoryLocator
和ContextSingletonBeanFactoryLocator
的JavaDoc来获得详细的例子。正如在EJB那章所提到的,Spring为EJB提供方便使用的基类,通常使用一个non-singleton的BeanFactoryLocator
实现,这样在需要时就可以很容易地被SingletonBeanFactoryLocator和ContextSingletonBeanFactoryLocator替换。